/* Copyright (C) 2005-2013, Unigine Corp. All rights reserved.
 *
 * File:    fragment_deferred_sample.h
 * Desc:    Decal deferred sample shader
 * Version: 1.03
 * Author:  Alexander Zapryagaev <frustum@unigine.com>
 *
 * This file is part of the Unigine engine (http://unigine.com/).
 *
 * Your use and or redistribution of this software in source and / or
 * binary form, with or without modification, is subject to: (i) your
 * ongoing acceptance of and compliance with the terms and conditions of
 * the Unigine License Agreement; and (ii) your inclusion of this notice
 * in any version of this software that you use or redistribute.
 * A copy of the Unigine License Agreement is available by contacting
 * Unigine Corp. at http://unigine.com/
 */

/******************************************************************************\
*
* OpenGL
*
\******************************************************************************/

#ifdef OPENGL
	
	#ifdef MULTISAMPLE_0
		half depth = getDeferredDepth(texture(s_texture_8,gl_FragCoord.xy * s_viewport.zw));
	#else
		int2 itexcoord = int2(gl_FragCoord.xy);
		half depth = getDeferredDepth(texelFetch(s_texture_8,itexcoord,0));
		for(int i = 1; i < MULTISAMPLE_SAMPLES; i++) {
			depth = max(depth,getDeferredDepth(texelFetch(s_texture_8,itexcoord,i)));
		}
	#endif
	
	float4 position = float4(normalize(s_texcoord_0.xyz) * (depth * s_depth_range.y),1.0f);
	
	half4 texcoord = mul4(s_decal_projection,position);
	texcoord.xy = texcoord.xy * base_transform.xy / texcoord.w + base_transform.zw;
	texcoord.z = 1.0f - dot(s_decal_plane,position);
	
	if(any(greaterThan(abs(texcoord.xyz - 0.5f),half3(0.5f)))) discard;
	
	#ifdef HAS_DEFERRED_NORMAL && (ANGLE || !SUBSTITUTE)
		half4 deferred_normal = texture2DDeferredRect(s_texture_9,gl_FragCoord.xy,s_material_textures[9].xy);
		half3 basis_normal = getDeferredNormal(deferred_normal);
	#endif
	
	#ifdef HAS_DEFERRED_NORMAL && ANGLE
		if(dot(basis_normal,s_decal_normal) < angle_threshold) discard;
	#endif
	
	#ifdef FADE
		half fade = s_decal_fade * texcoord.z;
	#else
		half fade = s_decal_fade;
	#endif
	
	half4 diffuse = texture2DAlpha(s_texture_0,texcoord.xy,fade);
	half3 normal = texture(s_texture_1,texcoord.xy).xyz;
	half4 specular = texture(s_texture_2,texcoord.xy);
	
	#ifdef OVERLAY || MULTIPLY
		
		half2 detail_texcoord = texcoord.xy * detail_transform.xy + detail_transform.zw;
		
		half4 detail_diffuse = texture(s_texture_3,detail_texcoord);
		half2 detail_normal = texture(s_texture_4,detail_texcoord).xy;
		half3 detail_specular = texture(s_texture_5,detail_texcoord).xyz;
		
		#ifdef ALPHA_TEST
			half3 blend = s_material_detail * detail_diffuse.w;
		#else
			half3 blend = s_material_detail * (diffuse.w * detail_diffuse.w);
		#endif
		
		#ifdef OVERLAY
			diffuse.xyz = saturate(diffuse.xyz + (detail_diffuse.xyz * 2.0f - 1.0f) * blend.x);
			specular.xyz = saturate(specular.xyz + (detail_specular.xyz * 2.0f - 1.0f) * blend.z);
		#else
			diffuse.xyz = diffuse.xyz * saturate(detail_diffuse.xyz + 1.0f - blend.x);
			specular.xyz = specular.xyz * saturate(detail_specular.xyz + 1.0f - blend.z);
		#endif
		normal.xy = normal.xy + detail_normal * blend.y;
		
	#endif
	
	diffuse *= diffuse_color;
	specular *= specular_color;
	
	normal.z = sqrt(saturate(1.0f - dot(normal.xy,normal.xy)));
	
	#ifdef USE_SRGB
		diffuse.xyz *= diffuse.xyz;
		specular.xyz *= specular.xyz;
	#endif
	
	#ifdef HAS_DEFERRED_NORMAL && !SUBSTITUTE
		normal.x += dot(s_decal_tangent,basis_normal);
		normal.y += dot(s_decal_binormal,basis_normal);
		normal.z = dot(s_decal_normal,basis_normal);
		normal = normalize(normal);
	#endif
	
	normal = s_decal_tangent * normal.x + s_decal_binormal * normal.y + s_decal_normal * normal.z;
	
	#ifdef ALPHA_TEST
		diffuse.w = saturate(diffuse.w * 2.0f - 1.0f);
	#endif
	
/******************************************************************************\
*
* Direct3D11
*
\******************************************************************************/

#elif DIRECT3D11
	
	#ifdef MULTISAMPLE_0
		half depth = getDeferredDepth(s_texture_8.SampleLevel(s_sampler_8,IN.position.xy * s_viewport.zw,0.0f));
	#else
		int2 itexcoord = int2(IN.position.xy);
		half depth = getDeferredDepth(s_texture_8.Load(itexcoord,0));
		[unroll] for(int i = 1; i < MULTISAMPLE_SAMPLES; i++) {
			depth = max(depth,getDeferredDepth(s_texture_8.Load(itexcoord,i)));
		}
	#endif
	
	float4 position = float4(normalize(IN.texcoord_0) * (depth * s_depth_range.y),1.0f);
	
	half4 texcoord = mul4(s_decal_projection,position);
	texcoord.xy = texcoord.xy * base_transform.xy / texcoord.w + base_transform.zw;
	texcoord.z = 1.0f - dot(s_decal_plane,position);
	
	if(any(abs(texcoord.xyz - 0.5f) > 0.5f)) discard;
	
	#ifdef HAS_DEFERRED_NORMAL && (ANGLE || !SUBSTITUTE)
		half4 deferred_normal = texture2DDeferredRect(s_texture_9,s_sampler_9,IN.position.xy,s_material_textures[9].xy);
		half3 basis_normal = getDeferredNormal(deferred_normal);
	#endif
	
	#ifdef HAS_DEFERRED_NORMAL && ANGLE
		if(dot(basis_normal,s_decal_normal) < angle_threshold) discard;
	#endif
	
	#ifdef FADE
		half fade = s_decal_fade * texcoord.z;
	#else
		half fade = s_decal_fade;
	#endif
	
	OUT = texture2DAlpha(s_texture_0,s_sampler_0,texcoord.xy,fade);
	
	half4 diffuse = OUT.color;
	half3 normal = s_texture_1.Sample(s_sampler_1,texcoord.xy).xyz;
	half4 specular = s_texture_2.Sample(s_sampler_2,texcoord.xy) * specular_color;
	
	#ifdef OVERLAY || MULTIPLY
		
		half2 detail_texcoord = texcoord.xy * detail_transform.xy + detail_transform.zw;
		
		half4 detail_diffuse = s_texture_3.Sample(s_sampler_3,detail_texcoord);
		half2 detail_normal = s_texture_4.Sample(s_sampler_4,detail_texcoord).xy;
		half3 detail_specular = s_texture_5.Sample(s_sampler_5,detail_texcoord).xyz;
		
		#ifdef ALPHA_TEST
			half3 blend = s_material_detail * detail_diffuse.w;
		#else
			half3 blend = s_material_detail * (diffuse.w * detail_diffuse.w);
		#endif
		
		#ifdef OVERLAY
			diffuse.xyz = saturate(diffuse.xyz + (detail_diffuse.xyz * 2.0f - 1.0f) * blend.x);
			specular.xyz = saturate(specular.xyz + (detail_specular.xyz * 2.0f - 1.0f) * blend.z);
		#else
			diffuse.xyz = diffuse.xyz * saturate(detail_diffuse.xyz + 1.0f - blend.x);
			specular.xyz = specular.xyz * saturate(detail_specular.xyz + 1.0f - blend.z);
		#endif
		normal.xy = normal.xy + detail_normal * blend.y;
		
	#endif
	
	diffuse *= diffuse_color;
	specular *= specular_color;
	
	normal.z = sqrt(saturate(1.0f - dot(normal.xy,normal.xy)));
	
	#ifdef USE_SRGB
		diffuse.xyz *= diffuse.xyz;
		specular.xyz *= specular.xyz;
	#endif
	
	#ifdef HAS_DEFERRED_NORMAL && !SUBSTITUTE
		normal.x += dot(s_decal_tangent,basis_normal);
		normal.y += dot(s_decal_binormal,basis_normal);
		normal.z = dot(s_decal_normal,basis_normal);
		normal = normalize(normal);
	#endif
	
	normal = s_decal_tangent * normal.x + s_decal_binormal * normal.y + s_decal_normal * normal.z;
	
	#ifdef ALPHA_TEST
		diffuse.w = saturate(diffuse.w * 2.0f - 1.0f);
	#endif
	
/******************************************************************************\
*
* Direct3D9
*
\******************************************************************************/

#elif DIRECT3D9
	
	half depth = getDeferredDepth(tex2Dproj(s_texture_8,IN.texcoord_7));
	
	float4 position = float4(normalize(IN.texcoord_0) * (depth * s_depth_range.y),1.0f);
	
	half4 texcoord = mul4(s_decal_projection,position);
	texcoord.xy = texcoord.xy * base_transform.xy / texcoord.w + base_transform.zw;
	texcoord.z = 1.0f - dot(s_decal_plane,position);
	
	if(any(abs(texcoord.xyz - 0.5f) > 0.5f)) discard;
	
	#ifdef HAS_DEFERRED_NORMAL && (ANGLE || !SUBSTITUTE)
		half4 deferred_normal = tex2Dproj(s_texture_9,IN.texcoord_7);
		half3 basis_normal = getDeferredNormal(deferred_normal);
	#endif
	
	#ifdef HAS_DEFERRED_NORMAL && ANGLE
		if(dot(basis_normal,s_decal_normal) < angle_threshold) discard;
	#endif
	
	#ifdef FADE
		half fade = s_decal_fade * texcoord.z;
	#else
		half fade = s_decal_fade;
	#endif
	
	half4 diffuse = tex2DAlpha(s_texture_0,texcoord.xy,fade);
	half3 normal = tex2D(s_texture_1,texcoord.xy).xyz;
	half4 specular = tex2D(s_texture_2,texcoord.xy);
	
	#ifdef OVERLAY || MULTIPLY
		
		half2 detail_texcoord = texcoord.xy * detail_transform.xy + detail_transform.zw;
		
		half4 detail_diffuse = tex2D(s_texture_3,detail_texcoord);
		half2 detail_normal = tex2D(s_texture_4,detail_texcoord).xy;
		half3 detail_specular = tex2D(s_texture_5,detail_texcoord).xyz;
		
		#ifdef ALPHA_TEST
			half3 blend = s_material_detail * detail_diffuse.w;
		#else
			half3 blend = s_material_detail * (diffuse.w * detail_diffuse.w);
		#endif
		
		#ifdef OVERLAY
			diffuse.xyz = saturate(diffuse.xyz + (detail_diffuse.xyz * 2.0f - 1.0f) * blend.x);
			specular.xyz = saturate(specular.xyz + (detail_specular.xyz * 2.0f - 1.0f) * blend.z);
		#else
			diffuse.xyz = diffuse.xyz * saturate(detail_diffuse.xyz + 1.0f - blend.x);
			specular.xyz = specular.xyz * saturate(detail_specular.xyz + 1.0f - blend.z);
		#endif
		normal.xy = normal.xy + detail_normal * blend.y;
		
		normal.xy = normal.xy * 2.0f - 1.0f - blend.y;
		
	#else
		
		normal.xy = normal.xy * 2.0f - 1.0f;
		
	#endif
	
	diffuse *= diffuse_color;
	specular *= specular_color;
	
	normal.z = sqrt(saturate(1.0f - dot(normal.xy,normal.xy)));
	
	#ifdef USE_SRGB
		diffuse.xyz *= diffuse.xyz;
		specular.xyz *= specular.xyz;
	#endif
	
	#ifdef HAS_DEFERRED_NORMAL && !SUBSTITUTE
		normal.x += dot(s_decal_tangent,basis_normal);
		normal.y += dot(s_decal_binormal,basis_normal);
		normal.z = dot(s_decal_normal,basis_normal);
		normal = normalize(normal);
	#endif
	
	normal = s_decal_tangent * normal.x + s_decal_binormal * normal.y + s_decal_normal * normal.z;
	
	#ifdef ALPHA_TEST
		diffuse.w = saturate(diffuse.w * 2.0f - 1.0f);
	#endif
	
/******************************************************************************\
*
* PlayStation3
*
\******************************************************************************/

#elif PLAYSTATION3
	
	half depth = getDeferredDepth(h4tex2Dproj(s_texture_8,IN.texcoord_9.xyw));
	
	float4 position = float4(normalize(IN.texcoord_0) * (depth * s_depth_range.y),1.0f);
	
	half4 texcoord = mul4(s_decal_projection,position);
	texcoord.xy = texcoord.xy * base_transform.xy / texcoord.w + base_transform.zw;
	texcoord.z = 1.0f - dot(s_decal_plane,position);
	
	if(any(abs(texcoord.xyz - 0.5f) > 0.5f)) discard;
	
	#ifdef HAS_DEFERRED_NORMAL && (ANGLE || !SUBSTITUTE)
		half4 deferred_normal = h4tex2Dproj(s_texture_9,IN.texcoord_9.xyw);
		half3 basis_normal = getDeferredNormal(deferred_normal);
	#endif
	
	#ifdef HAS_DEFERRED_NORMAL && ANGLE
		if(dot(basis_normal,s_decal_normal) < angle_threshold) discard;
	#endif
	
	#ifdef FADE
		half fade = s_decal_fade * texcoord.z;
	#else
		half fade = s_decal_fade;
	#endif
	
	half4 diffuse = tex2DAlpha(s_texture_0,texcoord.xy,fade);
	half3 normal = h3tex2D(s_texture_1,texcoord.xy);
	half4 specular = h4tex2D(s_texture_2,texcoord.xy);
	
	#ifdef OVERLAY || MULTIPLY
		
		half2 detail_texcoord = texcoord.xy * detail_transform.xy + detail_transform.zw;
		
		half4 detail_diffuse = h4tex2D(s_texture_3,detail_texcoord);
		half2 detail_normal = h2tex2D(s_texture_4,detail_texcoord);
		half3 detail_specular = h3tex2D(s_texture_5,detail_texcoord);
		
		#ifdef ALPHA_TEST
			half3 blend = s_material_detail * detail_diffuse.w;
		#else
			half3 blend = s_material_detail * (diffuse.w * detail_diffuse.w);
		#endif
		
		#ifdef OVERLAY
			diffuse.xyz = saturate(diffuse.xyz + (detail_diffuse.xyz * 2.0f - 1.0f) * blend.x);
			specular.xyz = saturate(specular.xyz + (detail_specular.xyz * 2.0f - 1.0f) * blend.z);
		#else
			diffuse.xyz = diffuse.xyz * saturate(detail_diffuse.xyz + 1.0f - blend.x);
			specular.xyz = specular.xyz * saturate(detail_specular.xyz + 1.0f - blend.z);
		#endif
		normal.xy = normal.xy + detail_normal * blend.y;
		
	#endif
	
	diffuse *= diffuse_color;
	specular *= specular_color;
	
	normal.z = sqrt(saturate(1.0f - dot(normal.xy,normal.xy)));
	
	#ifdef USE_SRGB
		diffuse.xyz *= diffuse.xyz;
		specular.xyz *= specular.xyz;
	#endif
	
	#ifdef HAS_DEFERRED_NORMAL && !SUBSTITUTE
		normal.x += dot(s_decal_tangent,basis_normal);
		normal.y += dot(s_decal_binormal,basis_normal);
		normal.z = dot(s_decal_normal,basis_normal);
		normal = normalize(normal);
	#endif
	
	normal = s_decal_tangent * normal.x + s_decal_binormal * normal.y + s_decal_normal * normal.z;
	
	#ifdef ALPHA_TEST
		diffuse.w = saturate(diffuse.w * 2.0f - 1.0f);
	#endif
	
#endif
